#include <memory>
#include <unistd.h>
#include <cstring>
#include <vector>
#include "Thread.hpp"
#include "Mutex.hpp"

int tickets = 10000;
// 1.如何看待锁
//   a.锁本身就是一个共享资源,全局的变量是要保护的,锁用来保护,可是锁也是全局资源,锁的安全谁来保护
//   b.pthread_mutex_lock,pthread_mutex_unlock:加锁的过程必须是安全的,加锁的过程其实是原子的
//   c.如果申请成功,就继续向后执行,如果申请暂时没有成功,执行流会阻塞
//   d.谁持有锁,谁进临界区
// 2.如何理解加锁和解锁的本质 ---- 加锁的过程是原子的
// 3.如果我们想简单的使用,如何进行封装设计
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

// 1.多个执行流进行安全访问的共享资源 --- 临界资源
// 2.我们把多个执行流中,访问临界资源的代码 --- 临界区
// 3.想让多个线程串行访问共享资源 --- 互斥
// 4.对一个资源进行访问,要么不做,要么做完 --- 原子性
// 对一个资源进行的操作,如果只用一条汇编就能完成 --- 原子性,反之不是原子的 --- 当前理解,方便表述

// 尽可能地让多个线程交叉执行
// 多个线程交叉执行本质:就是让调度器尽可能地频繁发生线程调度和切换
// 线程一般什么时候发生切换 -> 时间片到了,来了更高级优先级的线程,线程等待的时候
// 线程什么时候检测上面的问题 -> 从内核态返回用户态的时候,线程要对调度状态进行检测,如果可以,就直接发生线程切换

// 如何解决:加锁

class ThreadData
{
public:
    ThreadData(const string &threadname, pthread_mutex_t *mutex_p) : threadname_(threadname), mutex_p_(mutex_p)
    {
    }
    ~ThreadData() {}

public:
    string threadname_;
    pthread_mutex_t *mutex_p_;
};

void *getTicket(void *args)
{
    string username = static_cast<const char *>(args);
    // ThreadData *td = static_cast<ThreadData *>(args);
    while (true)
    {
        // 加锁和解锁的过程多个线程串行执行的,程序变慢了
        // 锁只规定互斥访问,没有规定必须让谁优先执行
        // 锁就是真的是多个线程进行竞争的结果

        // pthread_mutex_lock(&lock);
        // pthread_mutex_lock(td->mutex_p_);
        {
            LockGuard lockguard(&lock); // RAII风格
            if (tickets > 0)
            {
                usleep(1000); // 抢出负票
                // cout <<  td->threadname_ << "正在进行抢票: " << tickets << endl;
                cout << username << "正在进行抢票: " << tickets << endl;
                tickets--;

                // pthread_mutex_unlock(td->mutex_p_);
                // 用这段时间来模拟真实抢票花费的时间
                // usleep(1000);
                // pthread_mutex_unlock(&lock);

                // 对变量进行++或--,在C,C++上看起来只有一条语句,但是汇编后至少是3条语句
                // 1.从内存中读取数据到cpu寄存器中
                // 2.在寄存器中让cou进行对应的算逻运算
                // 3.写回新的结果到内存中变量的位置
            }
            else
            {
                // pthread_mutex_unlock(&lock);
                // pthread_mutex_unlock(td->mutex_p_);
                break;
            }
        }

        usleep(1000);
    }

    return nullptr;
}

int main()
{
    // #define NUM 4
    //     pthread_mutex_t lock;
    //     pthread_mutex_init(&lock, nullptr);
    //     vector<pthread_t> tids(NUM);
    //     for(int i = 0; i < NUM; i++)
    //     {
    //         char buffer[64];
    //         snprintf(buffer, sizeof(buffer), "thread %d", i + 1);
    //         ThreadData *td = new ThreadData(buffer, &lock);
    //         pthread_create(&tids[i], nullptr, getTicket, td);
    //     }

    //     for(const auto &tid:tids)
    //     {
    //         pthread_join(tid, nullptr);
    //     }

    pthread_t t1, t2, t3, t4;
    pthread_create(&t1, nullptr, getTicket, (void *)"thread 1");
    pthread_create(&t2, nullptr, getTicket, (void *)"thread 2");
    pthread_create(&t3, nullptr, getTicket, (void *)"thread 3");
    pthread_create(&t4, nullptr, getTicket, (void *)"thread 4");

    pthread_join(t1, nullptr);
    pthread_join(t2, nullptr);
    pthread_join(t3, nullptr);
    pthread_join(t4, nullptr);

    // pthread_mutex_destroy(&lock);

    // unique_ptr<Thread> thread1(new Thread(getTicket, (void *)"user1", 1));
    // unique_ptr<Thread> thread2(new Thread(getTicket, (void *)"user2", 2));
    // unique_ptr<Thread> thread3(new Thread(getTicket, (void *)"user3", 3));
    // unique_ptr<Thread> thread4(new Thread(getTicket, (void *)"user4", 3));

    // thread1->join();
    // thread2->join();
    // thread3->join();
    // thread4->join();
}